from bisect import bisect
from ftpext import ftpext 
from smbclient import SambaClient 
from time import strptime, mktime 
import re
import sys
import sqlite3

import os

def pyWatchCreateTables(db):
    if db:
        con = sqlite3.connect(db)
        cur = con.cursor()
        cur.executescript("""CREATE TABLE urls  (id         INTEGER PRIMARY KEY ASC,
                                url        TEXT UNIQUE,
                                last_enum  INTEGER,
                                last_error TEXT);
    
    
                             CREATE TABLE files (id         INTEGER PRIMARY KEY ASC,
                                url_id	    INTEGER,
                                name	    TEXT,
                                size        INTEGER,
                                mode        INTEGER,
                                atime	    INTEGER,
                                ctime       INTEGER,
                                mtime       INTEGER);""")
        cur.close()
        con.commit()
        con.close()
        
    return True





class pyWatchFile(object):
    def __init__(self, name = None, size = 0, mode = None, atime = None, ctime = None, mtime = None):
        self.name = name
        self.size = size
        self.mode = mode
        self.atime = atime
        self.ctime = ctime
        self.mtime = mtime

    def __eq__(self, other):
        if self.name == other.name:
	    return self.size == other.size and self.mtime == other.mtime  

	else:
	    return False
	return self.name == other.name

    def __gt__(self, other):
        return self.name >  other.name

    def __lt__(self, other):
        return self.name < other.name

    def __ge__(self, other):
        return self.name >= other.name

    def __le__(self, other):
        return self.name <= other.name

    def __ne__(self, other):
        return self.name != other.name





class pyWatchFolder(object):
    def __init__(self):
        self.db_con = None

    def registerDb(self, db_file = None):

        if db_file:
            if not os.path.isfile(db_file):
                if not pyWatchCreateTables(db_file):
                    return False
        
            try:	
                self.db_con = sqlite3.connect(db_file)
                self.db_con.text_factory = str
                return True
            except:
                return False


    def PyWatchDump(self, lst, url):

	if lst == []:
            pass
        else:
	    url_id = self.PyWatchInsertUrl(url)[0]
            if url_id:

                cur = self.db_con.cursor()
	
		for data in lst:
		    cur.execute("INSERT INTO files (url_id, name, size, mode, atime, ctime, mtime) VALUES (?,?,?,?,?,?,?)", (url_id, data.name, data.size, data.mode, data.atime,data.ctime,data.mtime))

		self.db_con.commit()
            	cur.close()



    def PyWatchDeleteFilesByUrlId(self, url_id):
        if self.db_con:
            #
            # Elimina de la base de datos todos los files de una URL
            #
            cur = self.db_con.cursor()
            cur.execute("DELETE FROM files WHERE url_id=?", [url_id] )
            self.db_con.commit()
            cur.close()


    def PyWatchDeleteFilesByUrl(self, url):
        return self.PyWatchDeleteFilesByUrlId(self.PyWatchGetUrlId(url)[0])



    def PyWatchGetUrlId(self, url):
        ret = None
        if self.db_con:
            #
            # Retorna el url_id o None
            #
            cur = self.db_con.cursor()
            cur.execute("SELECT id FROM urls WHERE url=?", [url])
            ret = cur.fetchone()
            cur.close()
        
        return ret


    def PyWatchGetFilesByUrl(self, url):
        lst_result = []
        if self.db_con:
            url_id = self.PyWatchInsertUrl(url)[0]
#	    print url_id
            if url_id:
                cur = self.db_con.cursor()
                cur.execute("SELECT name, size, mode, atime, ctime, mtime from files where url_id=?", [url_id])
                all = cur.fetchall()
                for name, size, mode, atime, ctime, mtime in all:
#      		    print name 
                    lst_result.append(pyWatchFile(name, size, mode, atime, ctime, mtime))

                cur.close()

            return lst_result 	


    def PyWatchInsertUrl(self, url):
        if self.db_con:
            try: 
                cur = self.db_con.cursor()
                cur.execute("INSERT INTO urls (url, last_enum, last_error) VALUES (?, 0, '')", (url,))		
                self.db_con.commit()
                cur.close()
            except:
		pass

            return self.PyWatchGetUrlId(url)


    def PyBinarySearch(self, lst, file):
	lo = 0
	hi = len(lst)

	return self.binary_search(lst,file, lo, hi) 


    def binary_search(self, a,x,lo=0,hi=-1):
        i = bisect(a,x,lo,hi)
        if i == 0:
            return False
        elif a[i-1] == x:
            return True
        else:
            return False



    def PyWatchGetFtpFiles(self, host, user, passwd, path ):
        lst_result = []
	ftp = ftpext(host)

	if ftp:
	    ftp.login(user, passwd)
	    ftp.cwd(path)
	    lst = ftp.nlst()
	    for file in lst:
		try:
		    size = ftp.size(file)
		    mdtm = ftp.mdtm(file)
		except:
		    size = 0
		    mdtm = 0
		lst_result.append(pyWatchFile(file, size, 0, 0, 0, mdtm))
	
	ftp.quit()
	ftp.close()

	return lst_result
	
	

    def PyWatchGetSmbFiles(self, host, user, passwd, share, path, onlyFiles = True ):
        lst_result = []

	smb =  SambaClient(server=host, share=share, username=user, password=passwd)

	lst_dir = smb.lsdir(path)
	for name, mode, size, date in lst_dir:
            mtime = mktime(date.timetuple())
	    if onlyFiles:
		if smb.isfile(path + name):
		    lst_result.append(pyWatchFile(name, size, mode, 0, 0, mtime))
	    else:
	        lst_result.append(pyWatchFile(name, size, mode, 0, 0, mtime))

	return lst_result


    
    def PyWatchGetLocalFiles(self, path, onlyFiles = True ):
        lst_result = []

	if not path.endswith('/'):
	    path = path + '/'       
 
        if os.path.exists(path):
            lst_dir = os.listdir(path)
            for file in lst_dir:
		if onlyFiles:
		    if os.path.isfile(path+file):
                        st = os.stat(path+file)			
                        lst_result.append(pyWatchFile(file, st.st_size, st.st_mode, st.st_atime, st.st_ctime, st.st_mtime))
		else:
		    st = os.stat(path+file)
                    lst_result.append(pyWatchFile(file, st.st_size, st.st_mode, st.st_atime, st.st_ctime, st.st_mtime))
	

        return lst_result



    def PyWatchMatch(self, name, include=None, exclude=None):

	if include:
	    if re.match(include, name):	
		#
		# Pasa por la lista blanca
		#
		if exclude:
		   if re.match(exclude, name):
			return False
		
		return True
	    else:
		return False

	if exclude:
		# 
		# Bloqueado por lista negra
		#
	    if re.match(exclude, name):
		return False

	return True	



    def PyWatchUrlProto(self, url):
        result = re.match("(local|ftp|smb):(.+)", url)
        if result:
            return result.group(1)

        return None

    def PyWatchUrlGetLocalPath(self, url):
	result = re.match("local:(.+)", url)
	return result.group(1)


    def PyWatchUrlGetFtpData(self, url):
	result = re.match("ftp://(.+):(.+)@(.+):(.+)", url)
	if result:
	    return result.group(1), result.group(2), result.group(3), result.group(4) 	
	
	return None


    def PyWatchUrlGetSmbData(self, url):
	
	result = re.match("smb://(.+):(.+)@(.+):/(.+)", url)

	if result:
	    if result.group(4):
		data = result.group(4).split('/')
		if len(data) > 0:
		    path  = '' 
		    share = data[0]
		    for d in data[1:]:
			path = path + '/' + d

		    path = path + '/'
	
	            return result.group(1), result.group(2), result.group(3), share, path 


    def Scan(self, url, include=None, exclude=None, onlyFiles=False):
	result = []
	

	proto = self.PyWatchUrlProto(url)
	if proto:
	    if proto == "local":
		path = self.PyWatchUrlGetLocalPath(url)

		if path:
		    local  = self.PyWatchGetLocalFiles(path, onlyFiles)

	    elif proto == "ftp":
		user, password, host, path = self.PyWatchUrlGetFtpData(url)
		if user and password and host and path:
		    local = self.PyWatchGetFtpFiles(host, user, password, path)

	    elif proto == "smb":
		user, password, host, share, path = self.PyWatchUrlGetSmbData(url)
		if user and password and host and path and share:
		    local = self.PyWatchGetSmbFiles(host, user, password, share, path, onlyFiles)



	    local.sort()

	    base   = self.PyWatchGetFilesByUrl(url)

	    for data in local:
	        if self.PyBinarySearch(base, data):
         	    pass 
                else:
                    if self.PyWatchMatch(data.name, include, exclude):
                        result.append(data)
	

	    self.PyWatchDeleteFilesByUrl(url)
	    self.PyWatchDump(local, url)

        return result


#watch = pyWatchFolder()
#watch.registerDb('./db')
#x = watch.Scan("smb://Administrator:Iplusb10@10.221.40.232:/rhozet/232_inbox/PROMOS_TO_TIBA", include='(.+).mov' )
#for i in x:
#    print i.name
